local json = require "cjson"

-------------------------------------------------------------------------------
---! CREATE TABLE TO HOLD RANK
-------------------------------------------------------------------------------
local user_cache_map = {}
local user_rank_num = 200
local user_rank_map = nil

-------------------------------------------------------------------------------
---! 内部方法
-------------------------------------------------------------------------------
---! 加载排行榜数据
local _last_load_time
local function load_rank_data()
    if user_rank_map then
        ---! 数据库数据仅需加载成功一次即可
        return true
    end

    local now = os.time()
    if _last_load_time and now - _last_load_time < 30 then
        return false
    end

    _last_load_time = now
    local ok, data = FILE_D:read_common_data("artifact_rank", user_rank_num)
    _last_load_time = nil

    if not ok then
        ---! 查询数据库失败
        return false
    end

    user_rank_map = data
    return true
end

---! 查询玩家数据
local function find_user_data(userid, user_rank_tmp)
    userid = tostring(userid)
    for idx = 1, #user_rank_tmp do
        local rank = user_rank_tmp[idx]
        if rank.userid == userid then
            return idx, rank
        end
    end
end

---! 同步排行榜缓存
local function sync_cache_data()
    local ok = load_rank_data()
    if not ok then
        return false
    end

    if table.size(user_cache_map) <= 0 then
        return true
    end

    ---! 每次同步使用全新数据，避免影响玩家个人缓存数据
    user_rank_map = table.copy(user_rank_map)

    ---! 同步一次玩家数据
    for userid, user_data in pairs(user_cache_map) do
        local _, rank = find_user_data(userid, user_rank_map)
        if not rank then
            table.insert(user_rank_map, user_data)
        else
            rank.level = user_data.level
            rank.rank_level = user_data.rank_level
            rank.nickname = user_data.nickname
            rank.context = user_data.context
        end
    end

    ---! 进行一次数据排序
    table.sort(user_rank_map, function (a, b)
        return a.rank_level * 10000 + a.level > b.rank_level * 10000 + b.level
    end)

    ---! 清理多余排名数据
    for idx = user_rank_num + 1, #user_rank_map do
        user_rank_map[idx] = nil
    end

    ---! 重置玩家缓存数据
    user_cache_map = {}
    return true
end

-------------------------------------------------------------------------------
---! 对外接口
-------------------------------------------------------------------------------
ARTIFACT_RANK_D = {}

---! 查询排行榜数据
function ARTIFACT_RANK_D:query_rank_data(player, from, to)
    local userid = player:get_id()
    if not userid then
        return
    end

    if from <= 1 then
        ---! 清理当前玩家缓存
        player:delete_temp("artifact_rank_map")
    end

    local user_rank_tmp = player:query_temp("artifact_rank_map")
    if not user_rank_tmp then
        ---! 同步排行榜数据
        local ok = sync_cache_data()
        if not ok then
            local result = {}
            result.code = 400
            result.status = "rank data load failed."
            result.name = "artifact_rank"
            player:send_packet("MSGS2CRankingList", result)
            return
        end

        ---! 生成排行榜缓存
        user_rank_tmp = player:set_temp("artifact_rank_map", user_rank_map)
    end

    ---! 查找玩家当前排名
    local inranking = find_user_data(userid, user_rank_tmp) or 0

    ---! 获取指定范围排名
    local data = {}
    local min = math.max(1, from)
    local max = to > 0 and math.min(#user_rank_tmp, to) or #user_rank_tmp
    for idx = min, max do
        local rank = user_rank_tmp[idx]
        table.insert(data, {
            ranking = idx,
            userid = rank.userid,
            name =  rank.nickname,
            level = rank.level,
            rank_level = rank.rank_level,
            context = rank.context,
        })
    end

    local result = {}
    result.code = 200
    result.status = "success"
    result.name = "artifact_rank"
    result.data = data
    result.inranking = inranking
    player:send_packet("MSGS2CRankingList", result)
end

---! 同步排行榜数据
function ARTIFACT_RANK_D:sync_rank_data(player)
    local userid = player:get_id()
    if not userid then
        return
    end

    local stage_level = player:get_stage_level()
    if stage_level <= 1 then
        return
    end

    local artifact_level = 0
    for _, artifact in pairs(player:query("artifact") or {}) do
        artifact_level = artifact_level + (artifact.level or 0)
    end
    if artifact_level < 1 then
        return
    end

    userid = tostring(userid)
    user_cache_map[userid] = {
        userid = userid,
        level = player:get_level(),
        nickname = player:get_nick_name(),
        rank_level = artifact_level,
        context = json.encode(player:query("player_dbase") or "") or "",
    }
end

-------------------------------------------------------------------------------
---! 启动模块
-------------------------------------------------------------------------------
register_post_init(function()
    ---! 服务器启动时，加载一次完整的排行榜数据
    return THREAD_D:create(load_rank_data)
end)
